package com.etung.iot.demo.services.impl;
import	java.security.KeyStore.Entry.Attribute;
import	java.util.jar.JarFile;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.etung.iot.demo.configs.TopicConfig;
import com.etung.iot.demo.constant.CommonConstant;
import com.etung.iot.demo.constant.TypeConstant;
import com.etung.iot.demo.core.SimplePageInfo;
import com.etung.iot.demo.dao.AccessInfoMapper;
import com.etung.iot.demo.dao.BoxMapper;
import com.etung.iot.demo.dao.VariantMapper;
import com.etung.iot.demo.modles.AccessInfo;
import com.etung.iot.demo.modles.RealData;
import com.etung.iot.demo.mqtt.EmqxClient;
import com.etung.iot.demo.mqtt.MqttQoS;
import com.etung.iot.demo.services.VariantMgrService;
import com.etung.iot.demo.utils.RedisUtil;
import com.etung.iot.demo.utils.TopicUtil;
import com.etung.iot.demo.vo.req.VariantControl;
import com.etung.iot.demo.vo.req.VariantQuery;
import com.etung.iot.demo.vo.resp.VariantRealData;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;

@Service
@Slf4j
public class VariantMgrServiceImp implements VariantMgrService {

    @Autowired
    private EmqxClient emqxClient;
    @Autowired
    private VariantMapper variantMapper;
    @Autowired
    private AccessInfoMapper accessInfoMapper;
    @Autowired
    private RedisUtil redisUtil;


    @Override
    public void controlVariant(VariantControl variant) {
        //校验变量参数是否合法
        log.info(variant.toString());
        String errorMessage = "";
        if (!StringUtils.isEmpty(variant.getVarDataType())){
            try {
                switch (variant.getVarDataType()){
                    case TypeConstant.INT_16:
                    case TypeConstant.UINT_16:{
                        int variantValue = Integer.parseInt(variant.getVarValue());
                        if (variantValue < Short.MIN_VALUE || variantValue > Short.MAX_VALUE) {
                            errorMessage = TypeConstant.INVALID_RANGE;
                        }
                    }
                        break;
                    case TypeConstant.INT_32:
                    case TypeConstant.UINT_32:{
                        long variantValue = Long.parseLong(variant.getVarValue());
                        if (variantValue < Integer.MIN_VALUE || variantValue > Integer.MAX_VALUE) {
                            errorMessage = TypeConstant.INVALID_RANGE;
                        }
                    }
                        break;
                    case TypeConstant.FLOAT:{
                         float value = Float.parseFloat(variant.getVarValue());
                    }
                    break;
                    case TypeConstant.DOUBLE :{
                        double value = Double.parseDouble(variant.getVarValue());
                    }
                    break;
                    case TypeConstant.BOOL:{
                        boolean value = Boolean.parseBoolean(variant.getVarValue());
                    }
                    break;
                    default :
                        break;

                }
            }catch (Exception e){
                throw new RuntimeException("设置变量参数非法！");
            }
        }
        if (!StringUtils.isEmpty(errorMessage)){
            throw new RuntimeException(errorMessage);
        }
        List<AccessInfo> accessInfos = accessInfoMapper.selectList(new QueryWrapper<AccessInfo>().eq("device_name", variant.getImei()).orderByDesc("create_time"));
        String productKey = "";
        if (accessInfos != null && accessInfos.size() >0){
            productKey = accessInfos.get(0).getProductKey();
        }
        if(!StringUtils.isEmpty(productKey)){
            JSONObject body = new JSONObject();
            JSONArray jsonArray = new JSONArray();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("id",variant.getVarId());
            jsonObject.put("value",variant.getVarValue());
            jsonArray.add(jsonObject);
            body.put("variants",jsonArray);
            String topic = TopicUtil.replaceGenPath(TopicConfig.VARIANT_CONTROL_TOPIC,productKey,variant.getImei());
            emqxClient.publish(MqttQoS.EXACTLY_ONCE.value(),false,topic,body.toJSONString());
        }else{
            throw new RuntimeException("productKey在数据库中未找到！");
        }
    }

    @Override
    public SimplePageInfo<?> listData(VariantQuery variantQuery) {
        log.info(variantQuery.toString());
        PageHelper.startPage(variantQuery.getPage(), variantQuery.getLimit());
//        List<VariantRealData> variantRealData = variantMapper.selectVarRealData(variantQuery);
        List<VariantRealData> variantRealData = variantMapper.selectVarInfo(variantQuery);
        //修改显示的变量地址
        updateAddressDisplay(variantRealData);
        //填充变量数据(状态、数据、上传时间)
        fillCacheData(variantRealData);
        PageInfo<VariantRealData> pageInfo = new PageInfo<>(variantRealData);
        return new SimplePageInfo<>(pageInfo);
    }

    private void fillCacheData(List<VariantRealData> variantRealDataList) {
        if (variantRealDataList != null && variantRealDataList.size() > 0){
            variantRealDataList.forEach(this::fillCacheData);
        }
    }

    private void fillCacheData(VariantRealData realData){
        String cacheKey =CommonConstant.REAL_DATA_CACHE_PREFIX + realData.getImei() +"_" + realData.getVarId();
        if (redisUtil.hasKey(cacheKey)){
            RealData old = (RealData)redisUtil.get(cacheKey);
            realData.setStatus(CommonConstant.GOOD);
            realData.setValue(old.getValue());
            realData.setTime(old.getTime());
        }
    }

    @Override
    public List<String> getVarIdByImei(String imei) {
        return variantMapper.selectVarIdByImei(imei);
    }

    @Override
    public List<String> getVarIdByDeviceId(String imei, Integer deviceId) {
        return variantMapper.selectVarIdByDeviceId(imei,deviceId);
    }

    private void updateAddressDisplay(List<VariantRealData> variantRealDataList){
        if (variantRealDataList != null && variantRealDataList.size() > 0){
            variantRealDataList.forEach(this::formatAddressTypeDisplay);
        }
    }

    private void formatAddressTypeDisplay(VariantRealData variantRealData){
        int base = 0;
        String res = "";
        if (variantRealData.getAddressType().equals(CommonConstant.COIL)){
            int offset= Integer.parseInt(variantRealData.getOffset().isEmpty()?"0":variantRealData.getOffset());
            base = 0;
            res = String.valueOf(base+ offset);
            if(res.length() < 6){
                StringBuilder sb = new StringBuilder();
                for(int i=0;i<6-res.length();i++){
                    sb.append("0");
                }
                sb.append(res);
                res = sb.toString();
            }
        }else if (variantRealData.getAddressType().equals(CommonConstant.DISCRETE)){
            int offset= Integer.parseInt(variantRealData.getOffset().isEmpty()?"0":variantRealData.getOffset());
            base = 100000;
            res = String.valueOf(base+ offset);
        }else if(variantRealData.getAddressType().equals(CommonConstant.THR)){
            int offset= Integer.parseInt(variantRealData.getOffset().isEmpty()?"0":variantRealData.getOffset());
            base = 400000;
            res = String.valueOf(base+ offset);
        }else if (variantRealData.getAddressType().equals(CommonConstant.IR)){
            int offset= Integer.parseInt(variantRealData.getOffset().isEmpty()?"0":variantRealData.getOffset());
            base = 300000;
            res = String.valueOf(base+ offset);
        }else{
            res = variantRealData.getAddressType() + variantRealData.getOffset();
            if (!variantRealData.getAddressType2().isEmpty()){
                res +=("." +variantRealData.getAddressType2() + variantRealData.getOffset2());
            }
        }
        variantRealData.setAddressDisplay(res);
    }


}
